package com.cfh.springcloudserver.controller;


import com.cfh.springcloudserver.annotation.SemaphoreCircuitBreaker;
import com.cfh.springcloudserver.annotation.TimeoutCircuitBreaker;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Random;
import java.util.concurrent.*;

@RestController
public class ServerController {

    private final Random random = new Random();

    private final ExecutorService executorService = Executors.newSingleThreadExecutor();

    @GetMapping("/say")
    @HystrixCommand(
            fallbackMethod = "errorContent",
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",
                            value = "100")
            })
    public String say(@RequestParam String message) throws InterruptedException {

        int value = random.nextInt(200);

        Thread.sleep(value);

        System.out.println("say() cost " + value + "ms");

        System.out.println("ServerController#say接收到消息：" + message);
        return "Hello," + message;
    }

    public String errorContent(String message) {
        return "Default";
    }


    /**
     * 简易版本（超时捕捉）
     *
     * @param message
     * @return
     */
    @GetMapping("/easysay")
    public String easysay(@RequestParam String message) {
        Future<String> future = executorService.submit(() -> {
            return doSay(message);
        });

        String returnValue = null;
        try {
            returnValue = future.get(100, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            returnValue = errorContent(message);
        }
        return returnValue;
    }


    /**
     * 中级版本（增强类捕捉超时异常）
     *
     * @param message
     * @return
     */
    @GetMapping("/middleSay")
    public String middleSay(@RequestParam String message) throws Exception {
        Future<String> future = executorService.submit(() -> {
            return doSay(message);
        });
        String returnValue = null;
        try {
            returnValue = future.get(100, TimeUnit.MILLISECONDS);
        } catch (TimeoutException e) {
            future.cancel(true);
            throw e;
        }
        return returnValue;
    }


    /**
     * 高级版本（AOP)
     *
     * @param message
     * @return
     */
    @GetMapping("/advancedSay")
    public String advancedSay(@RequestParam String message) throws Exception {
        return doSay(message);
    }

    /**
     * 终极版本（AOP+注解）
     *
     * @param message
     * @return
     */
    @GetMapping("/finalSay")
    @TimeoutCircuitBreaker(timeout = 100)
    public String finalSay(@RequestParam String message) throws Exception {
        return doSay(message);
    }

    /**
     * 终极版本（AOP+信号量）
     *
     * @param message
     * @return
     */
    @GetMapping("/finalSay2")
    @SemaphoreCircuitBreaker(value = 1)
    public String finalSay2(@RequestParam String message) throws Exception {
        return doSay(message);
    }


    /**
     * 执行体
     *
     * @param message
     * @return
     * @throws InterruptedException
     */
    private String doSay(String message) throws InterruptedException {

        int value = random.nextInt(200);

        System.out.println("say() cost " + value + "ms");

        Thread.sleep(value);

        return "other Say:" + message;
    }
}

